/** @file gui_stats.cpp
    @brief A stats page widget */

#include "gui/gui_stats.h"

using namespace G3;
using namespace GUI;

G3::GUI::STATS G3::GUI::MainStats;

//==============================================================================
// Constructors
//==============================================================================
G3::GUI::STATS_ENTRY::STATS_ENTRY (const std::string &aLabel, int aPriority) {
	Label = aLabel;
	Priority = aPriority;
}

G3::GUI::STATS_LABEL::STATS_LABEL (const std::string &aLabel, int aPriority):
	STATS_ENTRY (aLabel, aPriority) {
}

G3::GUI::STATS_INT_PTR::STATS_INT_PTR (const std::string &aLabel, int *aValue, int aPriority):
	STATS_ENTRY (aLabel, aPriority) {

	Value = aValue;
	RangeUsed = false;
	MinValue = 0;
	MaxValue = 0;
}

G3::GUI::STATS_FLOAT_PTR::STATS_FLOAT_PTR (const std::string &aLabel, float *aValue, int aPriority):
	STATS_ENTRY (aLabel, aPriority) {

	Value = aValue;
	RangeUsed = false;
	MinValue = 0;
	MaxValue = 0;
}

G3::GUI::STATS_VEC3F_PTR::STATS_VEC3F_PTR (const std::string &aLabel, VEC3F *aValue, int aPriority):
	STATS_ENTRY (aLabel, aPriority) {

	Value = aValue;
}

G3::GUI::STATS_ENTRY_PTR::STATS_ENTRY_PTR (STATS_ENTRY *aEntry) {
	pEntry = aEntry;
}

G3::GUI::STATS_PAGE::STATS_PAGE (FONT *aFont, const std::string &aLabel, const RECTI &aRect, int aPriority) {
	Group.Create (aRect, aFont, aLabel);
	AttachFont (aFont);
	Priority = aPriority;
	Editable = false;
}

G3::GUI::STATS_PAGE_PTR::STATS_PAGE_PTR (STATS_PAGE *aPage) {
	pPage = aPage;
}

G3::GUI::STATS::STATS () {
	//Editable = false;
}

//==============================================================================
// Destructors
//==============================================================================
G3::GUI::STATS_LABEL::~STATS_LABEL () {
}

G3::GUI::STATS_INT_PTR::~STATS_INT_PTR () {
}

G3::GUI::STATS_FLOAT_PTR::~STATS_FLOAT_PTR () {
}

G3::GUI::STATS_VEC3F_PTR::~STATS_VEC3F_PTR () {
}

G3::GUI::STATS_PAGE::~STATS_PAGE () {
	Clear ();
}

G3::GUI::STATS::~STATS () {
	Clear ();
}

//==============================================================================
// = operators
//==============================================================================
G3::GUI::STATS_ENTRY_PTR& G3::GUI::STATS_ENTRY_PTR::operator= (const STATS_ENTRY_PTR &e) {
	pEntry = e.pEntry;

	return *this;
}

G3::GUI::STATS_PAGE_PTR& G3::GUI::STATS_PAGE_PTR::operator= (const STATS_PAGE_PTR &p) {
	pPage = p.pPage;

	return *this;
}

G3::GUI::STATS_PAGE& G3::GUI::STATS_PAGE::operator= (const STATS_PAGE &aPage) {
	Priority = aPage.Priority;
	Entries = aPage.Entries;
	CurrentEntry = aPage.CurrentEntry;
	Font = aPage.Font;
	Group = aPage.Group;
	Editable = aPage.Editable;

	return *this;
}

//==============================================================================
// < operators
//==============================================================================
bool G3::GUI::STATS_ENTRY_PTR::operator< (const STATS_ENTRY_PTR &e) const {
	Assert (pEntry, "STATS_ENTRY_PTR::< Entry member is a NULL pointer");

	return (pEntry->Priority < e.pEntry->Priority);
}

bool G3::GUI::STATS_PAGE_PTR::operator< (const STATS_PAGE_PTR &p) const {
	Assert (pPage, "STATS_PAGE_PTR::< Page member is a NULL pointer");

	return (pPage->Priority < p.pPage->Priority);
}

//==============================================================================
// ::AttachFont
//==============================================================================
void G3::GUI::STATS_LABEL::AttachFont (FONT *aFont) {
	Assert (aFont, "STATS_LABEL::AttachFont: Font argument is a NULL pointer");

	Line.AttachFont (aFont);
}

void G3::GUI::STATS_INT_PTR::AttachFont (FONT *aFont) {
	Assert (aFont, "STATS_INT_PTR::AttachFont: Font argument is a NULL pointer");

	Line.AttachFont (aFont);
}

void G3::GUI::STATS_FLOAT_PTR::AttachFont (FONT *aFont) {
	Assert (aFont, "STATS_FLOAT_PTR::AttachFont: Font argument is a NULL pointer");

	Line.AttachFont (aFont);
}

void G3::GUI::STATS_VEC3F_PTR::AttachFont (FONT *aFont) {
	Assert (aFont, "STATS_VEC3F_PTR::AttachFont: Font argument is a NULL pointer");

	Line.AttachFont (aFont);
}

void G3::GUI::STATS_PAGE::AttachFont (FONT *aFont) {
	std::multiset<STATS_ENTRY_PTR>::iterator it;

	Assert (aFont, "STATS_PAGE::AttachFont: Font argument is a NULL pointer");

	Group.AttachFont (aFont);
	Font = aFont;

	it = Entries.begin ();
	while (it != Entries.end ()) {
		Assert (it->pEntry, "STATS_PAGE::AttachFont: Entry pointer member is invalid");
		it->pEntry->AttachFont (aFont);
		it++;
	}
}

//==============================================================================
// Adds an entry to the page
//==============================================================================
void G3::GUI::STATS_PAGE::AddEntry (STATS_ENTRY *aEntry) {
	Assert (aEntry, "STATS_PAGE::AddEntry: Entry argument is a NULL pointer");

	Entries.insert (STATS_ENTRY_PTR (aEntry));
	aEntry->AttachFont (Font);

	if (Entries.size () == 1)
		CurrentEntry = Entries.begin ();
}

void G3::GUI::STATS_PAGE::Clear () {
    Entries.clear ();
}

void G3::GUI::STATS::AttachFont (FONT *aFont) {
	std::multiset<STATS_PAGE_PTR>::iterator it;

	Assert (aFont, "STATS::AttachFont: Font argument is a NULL pointer");

	it = Pages.begin ();
	while (it != Pages.end ()) {
		Assert (it->pPage, "STATS::AttachFont: Page pointer member is invalid");
		it->pPage->AttachFont (aFont);
		it++;
	}
}

//==============================================================================
// Adds a page to the stats
//==============================================================================
void G3::GUI::STATS::AddPage (STATS_PAGE *aPage) {
	Assert (aPage, "STATS::AddPage: Page argument is a NULL pointer");

	Pages.insert (STATS_PAGE_PTR (aPage));

	if (Pages.size () == 1) {
		CurrentPage = Pages.begin ();

		// Add it to the gui
		MainGui.AddWidget (&MainGui.Root, this);
	}
}

//==============================================================================
// Sets the caption of a page
//==============================================================================
void G3::GUI::STATS_PAGE::SetCaption (const std::string &aCaption) {
	Group.SetCaption (aCaption);
}

//==============================================================================
// Drawing functions
//==============================================================================
void G3::GUI::STATS_LABEL::Draw (const VEC2I &Position, bool Highlighted, float aElapsedTime) {
	Line.SetPosition (Position);

    Line.Print ("%s", Label.c_str ());

	if (Highlighted)
		Line.Color = COL4F (1.0f, 1.0f, 1.0f, 1.0f);
	else
		Line.Color = COL4F (0.7f, 0.7f, 0.7f, 1.0f);

	Line.Draw (aElapsedTime);
}

void G3::GUI::STATS_INT_PTR::Draw (const VEC2I &Position, bool Highlighted, float aElapsedTime) {
	Line.SetPosition (Position);

	if (Value)
		Line.Print ("%s:  %d", Label.c_str (), *Value);
	else
		Line.Print ("%s:  N/A", Label.c_str ());

	if (Highlighted)
		Line.Color = COL4F (1.0f, 1.0f, 1.0f, 1.0f);
	else
		Line.Color = COL4F (0.7f, 0.7f, 0.7f, 1.0f);

	Line.Draw (aElapsedTime);
}

void G3::GUI::STATS_FLOAT_PTR::Draw (const VEC2I &Position, bool Highlighted, float aElapsedTime) {
	Line.SetPosition (Position);

	if (Value)
		Line.Print ("%s:  %f", Label.c_str (), *Value);
	else
		Line.Print ("%s:  N/A", Label.c_str ());

	if (Highlighted)
		Line.Color = COL4F (1.0f, 1.0f, 1.0f, 1.0f);
	else
		Line.Color = COL4F (0.7f, 0.7f, 0.7f, 1.0f);

	Line.Draw (aElapsedTime);
}

void G3::GUI::STATS_VEC3F_PTR::Draw (const VEC2I &Position, bool Highlighted, float aElapsedTime) {
	Line.SetPosition (Position);

	if (Value)
		Line.Print ("%s:  (%f, %f, %f)", Label.c_str (), Value->x, Value->y, Value->z);
	else
		Line.Print ("%s:  N/A", Label.c_str ());

	if (Highlighted)
		Line.Color = COL4F (1.0f, 1.0f, 1.0f, 1.0f);
	else
		Line.Color = COL4F (0.7f, 0.7f, 0.7f, 1.0f);

	Line.Draw (aElapsedTime);
}

void G3::GUI::STATS_PAGE::Draw (float aElapsedTime) {
	std::multiset<STATS_ENTRY_PTR>::iterator it;
	int y = Group.Rect.Top + 18;

	Group.Draw (aElapsedTime);

	it = Entries.begin ();
	while (it != Entries.end ()) {
		Assert (it->pEntry, "STATS_PAGE::Draw: Invalid Entry pointer member");

		if (y > Group.Rect.Bottom - 3)
			break;

		if (it == CurrentEntry)
			it->pEntry->Draw (G3::VEC2I (Group.Rect.Left + 3, y), true, aElapsedTime);
		else
			it->pEntry->Draw (G3::VEC2I (Group.Rect.Left + 3, y), false, aElapsedTime);

		y += 18;
		it++;
	}
}

void G3::GUI::STATS::NextPage () {
    CurrentPage++;

    if (CurrentPage == Pages.end ())
        CurrentPage = Pages.begin ();
}

void G3::GUI::STATS::PreviousPage () {
    if (CurrentPage == Pages.begin ())
        CurrentPage = Pages.end ();

    CurrentPage--;
}

void G3::GUI::STATS::Clear () {
    Pages.clear ();
}

void G3::GUI::STATS::Draw (float aElapsedTime) {
	if (Visible) {
		Assert (CurrentPage->pPage, "STATS::Draw: Current Page pointer is invalid");

		CurrentPage->pPage->Draw (aElapsedTime);
	}
}
